#pragma once
#include "MFUI.hpp"
#include<string.h>
#include<time.h>
#include<map>

namespace VN{
    class SceneState;
    typedef struct BackInfo{
        unsigned int length;
        Uint8 a;
        bool visible;
        char* name;
    }BackInfo;
    struct CharacterInfo{
        SDL_Rect rect;
        char* name;
        vector<BackInfo> ch;

        ~CharacterInfo();
    };
    //用于提供多语言的名称支持
    typedef unordered_map<string,const vector<TextMod>> NameUnit;
    class CGImage:public Image{
        public:
        SDL_Texture* cg;
        bool handle;//是否由开发者手动调控，默认false
        CGImage(Window* w);
        void _release(int x,int y,int clicks,unsigned char key);
        void Show(SDL_Texture* t);
        void _draw();
    };
    typedef struct CGPack{
        SDL_Texture* t;
        bool unlock;
    }CGPack;
    typedef void(*SaveFunc)(FILE*);
    enum scene_change_t{
        sc_default=0,//切换背景 淡出淡入
        sc_dissolve,//交叉显示
        sc_cg_fade,//慢速
        sc_cg_dissolve//慢速
    };
    enum shake_t{
        shake_vertical=0,shake_horizontal,shake_circle
    };
    class SaveObject;
    class GameScene;
    class ChooseButton;
    typedef void(*Logic)(GameScene*);
    typedef struct ResPair{
        SDL_Texture* src;
        bool visible;
    }ResPair;
    typedef struct ResGroup{
        const char* name;
        const char* dir;
    }ResGroup;
    class ResUnit{
        public:
        unordered_map<string,size_t> res_map;
        vector<ResPair> res;

        ResUnit(Renderer*,MFPack& pack,const char* dir);
        ~ResUnit();
    };
    class NameImage:public Image{
        SDL_Texture* _name;
        SDL_Rect _rect;//name计算后的居中矩形
        GameScene* g;
        public:
        vector<TextMod> cache;
        void SetName(const NameUnit& name);
        void SetName(const vector<TextMod>& name);
        void SetName();//置空
        NameImage(GameScene* g,SDL_Rect& r,const char* back_path);
        ~NameImage();
        void _draw();
    };
    class LayerImage:public Control{
        typedef struct RenderUnit{
            ResPair *s;
            SDL_Rect r;
        }RenderUnit;
        friend class GameScene;
        ResUnit* unit;
        unsigned char alpha;
        vector<RenderUnit> render;
        vector<const char*> last;//随render同步
        public:
        double angle;
        SDL_RendererFlip flip;
        //将当前的图层状态写入文件中 形式见SaveObject
        void QueryLayer(FILE* fp);
        void QueryLayer(vector<BackInfo>& a);
        unsigned char Alpha();
        size_t GetMemberNum();
        //默认透明度为0<name,path> 传入前请检查
        LayerImage& SetNewImage(ResUnit* u);
        //默认透明度为0<name,path> names传入前请检查
        LayerImage(Window* win,ResUnit*,SDL_Rect& r);
        ~LayerImage();
        void _draw();
        void SetPosition(int x,int y);
        void OffsetPosition(int x,int y);
        void SetSize(int w,int h);

        ResUnit* Res();
        LayerImage& Reset();
        LayerImage& SetLayerVisible(bool v);
        LayerImage& SetAlpha(const char* name,unsigned char a);
        //清理渲染列表
        LayerImage& ClearLayer();
        //从尾部移除n个,不要在无东西时调用！
        LayerImage& PopLayer(size_t n);
        //必须同时满足可见+在列表内
        LayerImage& AddLayer(initializer_list<const char*>name);
        LayerImage& AddLayer(vector<const char*>&name);
        LayerImage& SetLayerVisible(initializer_list<const char*> name,bool v);
        LayerImage& SetLayerVisible(vector<const char*>& name,bool v);
        //已添加层的所有
        LayerImage& SetAlpha(unsigned char a);
        LayerImage& SetAlpha(initializer_list<const char*> name,unsigned char v);
        LayerImage& SetAlpha(vector<const char*>& name,unsigned char v);
        LayerImage& ApplyChange(void(*)(SDL_Rect&));
    };
    struct Sentence{
        vector<TextMod> text;
        Logic logic;
    };
    struct LanguageContent{
        const char* language;
        vector<Sentence> sentence;
    };
    //不同语言内容需要等长content
    struct TextLabel{
        const char* name;
        vector<LanguageContent> content;
    };
    struct UIConfig{
        const char* language;
        vector<const char*> text;
    };
    typedef void(*Action)(GameScene*,int);
    class Chapter{
        class Pack{
            public:
            const vector<TextMod>* text;
            Logic logic;
            Pack(Logic,const vector<TextMod>*);
        };
        public:
        unordered_map<string,vector<Pack>> content;
        unordered_map<string,unordered_map<string,size_t>> label;
        vector<Pack>::iterator pos;
        Chapter(initializer_list<const vector<TextLabel>*> c);
    };
    class GameScene:public Control{
        void LoadSound();
        void LoadAudio();
        class ActionPack;
        class ActionPack{
            public:
            GameScene* g;
            int t;
            Action f;
            list<ActionPack*>::iterator pos;

            ActionPack(GameScene* g,int t,Action f);
        };
        static void ActionCallback(ActionPack*);
        static void ActionFinish(ActionPack*);
        class DissolvePack{
            public:
            GameScene* g;
            LayerImage* l;
            vector<const char*> last,next;
            unsigned int t;
            DissolvePack(GameScene*,LayerImage*,initializer_list<const char*>&next);
            DissolvePack(GameScene*,LayerImage*,initializer_list<const char*>& last
            ,initializer_list<const char*>&next);
        };
        static void DissolveCallback(DissolvePack*);
        static void DissolveSlowCallback(DissolvePack*);
        static void DissolveFinish(DissolvePack*);
        list<ActionPack*> actions;
        unsigned int naction;
        SDL_Texture *effect_t,*music_t,*progress_t;
        static void DialogCallback(GameScene*);
        static void GameBackFadein(LayerImage*);
        static void GameBackFinish(GameScene*);
        static void GameDialogFadein(AutoPlayText*);
        static void GameDialogFadeout(AutoPlayText*);
        static void GameEntered(GameScene*);
        static void ShakeCallback(GameScene*,int);

        static void AutoPlayCallback(GameScene*);

        Font* main_font;
        vector<SDL_Color> control_color;
        MFPack pack;

        const char* main_music;
        Task* _auto;
        vector<int> ui_size;//仅针对标题画面自定义
        unordered_map<string,UIConfig> ui_config;
        unordered_map<string,ResUnit*> res;
        unordered_map<string,Mix_Chunk*> sound;
        unordered_map<string,Mix_Music*> audio;
        unordered_map<string,SaveObject*> save;
        map<string,CGPack> cg;

        vector<Chapter*> chapter;
        vector<Chapter*>::iterator cur_ch;

        //返回 CG列表

        TextButton* cg_go_back;
        ListView* cg_view;
        CGImage* cg_whole;
        

        //返回 存档列表 确认

        TextButton *save_go_back,*confirm;
        InputBox* save_name;
        ListView* save_list;
        SaveFunc save_f,load_f;

        //音效/配音+BGM(音量条+禁用启用) 返回

        TextButton* option_go_back,*speed_normal,*speed_fast,*back_main;
        CheckBox *effect_box,*music_box;
        TextureBar *effect_bar,*music_bar;
        Label *effect_text,*music_text,*speed_text,*bgm_text;
        DropList* language_select;
        ListView* music_list;

        //新游戏 读档 CG 退出 背景图

        unordered_map<string,SDL_Texture*> backs;
        CGImage* main_back;
        TextButton *start_game,*load,*enter_cg,*quit,*main_option,*skip;

        //对话框 人名 设置 自动播放(开关)

        unordered_map<string,LayerImage*> character;//单独控制渲染 group,ptr
        vector<ChooseButton*> choose;//单独控制渲染
        TextButton* auto_play,*go_save,*go_option,*go_load,*open_backlog;
        SDL_Color default_text_color;
        ListView* backlog;

        Image* general_back;

        ProgressBar* limit_time;//限时选择的进度条
        double limit_value;//每帧扣除的进度条值

        Action next_action;
        int music_volume,effect_volume,next_time;
        bool music_mute,effect_mute;
        bool in_main,in_game,on_choose;
        bool fade_end,dialog_state,name_state,need_lock;
        //处理cur_ch的文本 调用逻辑后再进来

        LayerImage* flash_target;
        SDL_Rect flash_area;

        SDL_Color flash_color;
        bool is_flash,flash_in,flash_mode;//mode=true->颜色 false->纹理
        int flash_value;//每次增或减的值 通过color.a/t计算
        size_t flash_time;//启用后检测，到0为止
        Task* flash_task;
        size_t flash_t,flash_duration;

        bool is_load,is_gaming;//存档(F)/读档(T) is_gaming->决定是继续游戏还是新游戏

        vector<TextMod> last_name;

        void ProcessText();

        static void SceneChangeFade(GameScene*);
        static void SceneChangeFade2(GameScene*);
        static void SceneChangeFade3(GameScene*);
        static void CGChangeFade(GameScene*);
        static void CGChangeFade2(GameScene*);
        static void CGChangeFade3(GameScene*);
        static void SceneFadeFinish(GameScene*);
        static void CharacterFadein(LayerImage*);
        static void CharacterFadeout(LayerImage*);
        static void FlashCheck(GameScene*);
        static void FlashCheckTexture(GameScene*);
        //背景
        static void MainFadein1(GameScene*);
        //中转
        static void MainFadein2(GameScene*);
        //按钮
        static void MainFadein3(GameScene*);

        vector<const char*>next_scene_name,last_scene_name;
        const char* cur_language;
        Task* limit_task;
        //保存上一句到历史记录里
        void SaveBackLog();
        static void ChooseLimit(GameScene*);
        public:
        const char* version;//四位长字符串 少于4出错 大于4取前四位
        const char* music_cache;
        LayerImage*game_back;
        NameImage* name;
        AutoPlayText* dialog;
        //通过代码执行保存
        void Save(const string& name);
        //通过代码执行加载
        void Load(const string& name);
        bool IsGaming();
        SceneState* GetState();
        const char* CurrentLanguage();
        //获取资源组
        ResUnit* QueryRes(const char* name);
        void SetLanguage(const char* lang);
        //跳过所有动画并往后播放一格
        void Skip();
        //从mainback备选项里设置
        void SetMainBackground(const char* name);
        //在cg鉴赏调用 放大图
        void ShowCG(SDL_Texture* t);
        //获取当前所在的章节下标，所在句子下标和跳过数组长度以及所在文本长度
        void GetChapterInfo(size_t& ch,size_t& index);
        //total将加上SaveObject的所有所需数据
        SceneState* QueryState(FILE* fp,size_t& total);
        bool IsAutoPlay();
        bool IsCGUnlock(initializer_list<const char*>);
        //由确认按钮调用
        void ConfirmSave();
        //设置存档输入框的显示内容
        void SetSaveInput(const char* text);
        //做过渡动画
        void StartGame();
        //默认关闭
        void AutoPlay();
        void MuteEffect();
        void MuteMusic();
        void SetMusicVolume(double p);
        void SetEffectVolume(double p);
        void SetAutoSpeed(bool fast);
        //重定位到指定章节指定句子位置
        void Redirect(unsigned int ch,unsigned int index);
        //如果结束游戏返回主界面 需要玩家新游戏(二周目)才能保存
        GameScene& UnlockCG(const char* name);
        GameScene& Flash(LayerImage* target,SDL_Rect area,unsigned char target_alpha,size_t times,size_t t);
        GameScene& Flash(SDL_Color color,size_t times,size_t t);
        //换掉当前的
        GameScene& ChangeBackground(initializer_list<const char*>visible_name,unsigned int mode=sc_default);
        GameScene& SetBackgroundVisible(const char* name,bool v);
        //group如不存在会返回0 不要重复添加
        LayerImage* AddCharacter(const char* group,
        initializer_list<const char*>visible_name,SDL_Rect& r);
        //不存在会返回0
        LayerImage* GetCharacter(const char* group);
        //存在时才生效
        GameScene& RemoveCharacter(const char* group);
        GameScene& Fadein(LayerImage*);
        //锁定一次当前对话框(不往后走)
        GameScene& Lock();
        //往后播放文本
        GameScene& Next();
        //对话框淡出并禁用
        GameScene& HideDialog();
        //对话框淡入并启用
        GameScene& ShowDialog();
        GameScene& Fadeout(LayerImage*);
        GameScene& CrossDissolve(LayerImage*,initializer_list<const char*>& next);
        GameScene& CrossDissolve(LayerImage*,initializer_list<const char*> last,
        initializer_list<const char*> next);
        GameScene& CrossDissolveSlow(LayerImage*,initializer_list<const char*>& next);
        GameScene& CrossDissolveSlow(LayerImage*,initializer_list<const char*> last,
        initializer_list<const char*> next);
        GameScene& StopMusic();
        GameScene& ShakeBackground(int times);
        GameScene& StopSound();
        //在下一段文本播放时触发(仅限一个 多调用会覆盖 在调用结束后会马上重置)
        GameScene& NextAction(int t,Action f);
        //用以保证音频的播放时间不受玩家点击和自动播放的影响
        GameScene& Wait(int t);
        //当所有动作都结束后才会解锁用户操作
        GameScene& AddAction(int t,Action a);
        //无后缀 会播放times+1次
        GameScene& PlaySound(const char* name,int times);
        //无后缀 默认单曲循环
        GameScene& PlayMusic(const char* name);
        //跳转到指定标签处
        GameScene& Jump(const char* name);
        GameScene& Choose(vector<TextMod>,vector<Sentence>);
        GameScene& Choose(vector<TextMod>,vector<Sentence>,int t,void(*timeout)(GameScene*));
        //调用后析构所有的按钮
        void EndChoose();
        //主界面
        void EnterMain();
        //进入游戏中
        void EnterGame();
        void EnterCG();
        void EnterSave();
        void EnterLoad();
        void EnterOption();
        void EndGame();
        void OpenBackLog();
        void _draw();
        void _draw_edge();
        void Back();
        //析构时释放chapter指针 res_pair<group_name,pair<path,res_name>>
        GameScene(const char* default_language,Font* main_font,initializer_list<SDL_Color> main_color,initializer_list<int> control_size,initializer_list<UIConfig> config,const char* version,Window* w,SDL_Color default_text_color,const char* main_back_path,const char* init_main_back,
        const char* general_back_path,const char* dialog_back,const char* name_back,
        const char* back_group_name,const char* first_game_back,const char* main_music,SDL_Color time_color,
        initializer_list<ResGroup>& 
        res_pair,initializer_list<Chapter*>& chapters,SaveFunc sf,
        SaveFunc lf,vector<SDL_Point> control_pos,const char* progress_bg,const char* effect_fg,const char* music_fg);
        ~GameScene();
        void SetEnable(bool v);
        void SetVisible(bool v);
        void _release(int x,int y,int clicks,unsigned char key);
        void _press(int x,int y,int clicks,unsigned char key);
        void _mouse_wheel(SDL_MouseWheelEvent& event);
        void _mouse_move(int x,int y);
    };
    //用于保存单点场景内的信息
    class SceneState{
        public:
        vector<char*> cache;
        vector<TextMod> content,name;
        vector<BackInfo> back;
        vector<CharacterInfo> character;
        string music;
        size_t index,ch;
        size_t total;
        void Write(FILE* fp);
        void Load(GameScene* g);
        void Load(FILE* fp);
        ~SceneState();
        SceneState(const SceneState& v);
        SceneState();
    };
    class SaveItem;
    /*保存在游戏目录的save文件夹内 不支持backlog保存(会占用很大空间) 元数据固定长度=16
    文件格式："LBVN"+版本号(0000~9999)+名字长度(4)
    +名字(与文件名一致)+时间字符串(64)
    +[名称长度(4)+所在文本长度(4)+音乐名长度(4)+记录点立绘数(4)+记录点背景数(4)+记录点下标(4)+所在章节(4)+下4 元数据长度=36(32)]
    +音乐名
    +[文本长度(4)+颜色(rgba)+样式(4)+hint(4)+缩放比例(double)+文本]//默认不换行 有序 名称
    +[文本长度(4)+颜色(rgba)+样式(4)+hint(4)+是否换行(1)+缩放比例(double)+文本]//具体文本
    +[背景长度(4)+Alpha+是否可见+背景名]//有序
    +[组名长度(4)+组图个数(4)+矩形(SDL_Rect)+组名+[组图长度(4)+Alpha+是否可见+组图名]]//外无序 内有序
    +自定义数据

    公共数据选择读入时直接进入GameScene，初始化时只针对元数据读取
    */
    class SaveObject{
        public:
        SaveItem* item;//创建时关联上
        class SaveException:exception{};
        char* name;
        char* time_s;
        char version[4];
        size_t total;
        SceneState* state;

        //是否已存在在调用前检查 新增存档时以调用时时间作为保存时间 f用于写入公有数据外的自定义数据
        SaveObject(GameScene* g,const string n,SaveFunc f);
        //从文件中读 用于游戏初始化时调用(已知完整路径)
        SaveObject(const char* path);
        //f用于读入自定义数据
        void Load(GameScene* g,SaveFunc f);
        ~SaveObject();
    };
}